package com.company.zhishidian.thread;

import java.util.ArrayList;
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 多线程  线程同步
 * 公共资源竞争的问题
 */
public class DuoXC {
    public static void main(String[] args) throws InterruptedException {
        // 线程不安全的类
        ArrayList<Integer> list = new ArrayList<>();
        // 线程安全，但性能太差，已被淘汰
        Vector<Integer> v = new Vector<>();
        Thread th1 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
//                list.add(i);
                v.add(i);
            }
        });
        Thread th2 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
//                list.add(i);
                v.add(i);
            }
        });
        th1.start();
        th2.start();
        th1.join();
        th2.join();
        System.out.println(list.size());
        System.out.println(v.size());
    }
}

/**
 * 狗吃肉例子
 * 方法-
 */
class Guantou{
    static int meat = 1;
}
class Dog extends Thread{
    @Override
    public void run() {
        // 加同步锁会消耗性能，但增加了代码的原子性，线程处于阻塞状态
        synchronized (Guantou.class){
            if(Guantou.meat>=1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Guantou.meat--;
                System.out.println(this+"吃了一块肉");
            }
        }
    }
}
class TestDog{
    public static void main(String[] args) throws InterruptedException {
        Dog d1 = new Dog();
        d1.setName("汤姆");
        Dog d2 = new Dog();
        d2.setName("杰瑞");
        d1.start();
        d2.start();
        d1.join();
        d2.join();
        System.out.println("还剩"+Guantou.meat+"块肉");
    }
}
/**
 * 狗吃肉例子
 * 方法二
 */
class Guantou2{
    private int meat = 1;

    public  int getMeat() {
        return meat;
    }

    public void setMeat(int meat) {
        this.meat = meat;
    }
}
class Dog2 extends Thread{
    private Guantou2 guantou;

    public Dog2(Guantou2 guantou){
        this.guantou = guantou;
    }

    @Override
    public void run() {
        // 加对象锁
        synchronized (guantou){
            if(guantou.getMeat()>=1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                guantou.setMeat(guantou.getMeat()-1);
                System.out.println(this+"吃了一块肉");
            }
        }
    }
}
class TestDog2{
    public static void main(String[] args) throws InterruptedException {
        Guantou2 guantou2 = new Guantou2();
        Dog2 d1 = new Dog2(guantou2);
        d1.setName("汤姆");
        Dog2 d2 = new Dog2(guantou2);
        d2.setName("杰瑞");
        d2.start();
        d1.start();
    }
}

/**
 * 狗吃肉例子
 * 方法三
 */
class Guantou3{
    private int meat = 1;

    public  int getMeat() {
        return meat;
    }

    public void setMeat(int meat) {
        this.meat = meat;
    }

    // synchronized 对象内置锁
    public synchronized void eated(){
        // 加对象锁
            if(this.meat>=1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.meat--;
                System.out.println(this+"吃了一块肉");
            }
    }
}
class Dog3 extends Thread{
    private Guantou3 guantou;

    public Dog3(Guantou3 guantou){
        this.guantou = guantou;
    }

    @Override
    public void run() {
        guantou.eated();
    }
}
class TestDog3{
    public static void main(String[] args) throws InterruptedException {
        Guantou3 guantou = new Guantou3();
        Dog3 d1 = new Dog3(guantou);
        d1.setName("汤姆");
        Dog3 d2 = new Dog3(guantou);
        d2.setName("杰瑞");
        d2.start();
        d1.start();
    }
}

/**
 * 狗吃肉例子
 * 方法四
 * 新方法 锁
 */
class Guantou4{
    // 重入锁
    private ReentrantLock lock = new ReentrantLock();
    private int meat = 1;

    public  int getMeat() {
        return meat;
    }

    public void setMeat(int meat) {
        this.meat = meat;
    }

    public void eated(){
        // 重入锁，枷锁
        lock.lock();
        try{
            // 加对象锁
            if(this.meat>=1){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.meat--;
                System.out.println(this+"吃了一块肉");
            }
        }finally {
            // 释放锁
            lock.unlock();
        }
    }
}

class Dog4 extends Thread{
    private Guantou4 guantou;

    public Dog4(Guantou4 guantou){
        this.guantou = guantou;
    }

    @Override
    public void run() {
        guantou.eated();
    }
}
class TestDog4{
    public static void main(String[] args) throws InterruptedException {
        Guantou4 guantou = new Guantou4();
        Dog4 d1 = new Dog4(guantou);
        d1.setName("汤姆");
        Dog4 d2 = new Dog4(guantou);
        d2.setName("杰瑞");
        d2.start();
        d1.start();
    }
}

/**
 * 死锁
 *
 */
class DeadLok{
    class A{

    }
    class B{

    }
    private A a = new A();
    private B b = new B();
    public void method1() {
        synchronized (a){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (b){
            }
        }
    }
    public void method2() {
        synchronized (b){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (a){
            }
        }
    }

    public static void main(String[] args) {
        DeadLok d1 = new DeadLok();
        new Thread(()->{
            d1.method1();
        }).start();
        new Thread(()->{
            d1.method2();
        }).start();
    }
    /**
     * volatile 关键字  多线程中应用相当于保证了数据的原子性
     * 1. 可见性   可以让数据在被改变后加到内存中，使另一个线程也可见
     * 2. 有序性   在代码运行过程中其实不是按顺序执行的，会有一些改变，加了这个关键字就会保证执行顺序
     */

}